package com.linshengjian.snowball.payment.handler;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.linshengjian.snowball.payment.IPaymentHandler;
import com.linshengjian.snowball.payment.PaymentProperties;
import com.linshengjian.snowball.payment.event.PaymentCompleteEvent;
import com.linshengjian.snowball.payment.exception.PaymentBusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Slf4j
@Component
public class AlipayHandlerImpl implements IPaymentHandler {

    @Autowired
    private ApplicationContext context;

    @Autowired
    protected PaymentProperties properties;

    protected AlipayClient client;

    @PostConstruct
    private void init() {
        client = new DefaultAlipayClient(
                properties.getAliPay().getServerUrl(),
                properties.getAliPay().getAppId(),
                properties.getAliPay().getPrivateKey(),
                "json",
                "UTF-8",
                properties.getAliPay().getPublicKey(),
                "RSA2");
    }

    @Override
    public Object payment(String voucher, Double amount, String title, String body) throws Exception {
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(title);
        model.setSubject(body);
        model.setOutTradeNo(voucher);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(amount.toString());
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(properties.getCallbackDomainName() + properties.getCallbackUrl() + "/aliPay" );

        //这里和普通的接口调用不同，使用的是sdkExecute
        AlipayTradeAppPayResponse response = client.sdkExecute(request);
        return response.getBody();//就是orderString 可以直接给客户端请求，无需再做处理。
    }

    @Override
    public void refund(String refundVoucher, String paymentVoucher, Double amount) throws Exception {

        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();

        model.setOutTradeNo(paymentVoucher);
        model.setRefundAmount(String.valueOf(amount));
        model.setOutRequestNo(refundVoucher);

        request.setBizModel(model);
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeRefundResponse response = client.execute(request);
            if (response.isSuccess()) {
                log.info("退款成功，支付宝单号：" + response.getTradeNo());

                PaymentCompleteEvent event = new PaymentCompleteEvent(this, refundVoucher, response.getTradeNo(), response.getGmtRefundPay());

                context.publishEvent(event);
            }
            throw new PaymentBusinessException("支付宝退款失败，请联系客服处理");
        } catch (AlipayApiException e) {
            log.error(e.getMessage(), e);
            throw new PaymentBusinessException(e.getMessage(), null);
        }
    }

    @Override
    public void refresh(String voucher) {

    }

    public String callback(HttpServletRequest request, HttpServletResponse response) {
        try {
            //获取支付宝POST过来反馈信息
            Map<String,String> params = new HashMap<>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用。
                //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }
            //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
            //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
            boolean flag = AlipaySignature.rsaCheckV1(params, properties.getAliPay().getPublicKey(), "UTF-8", params.get("sign_type"));
            if(flag){
                // TODO 验签成功后
                //按照支付结果异步通知中的描述，对支付结果中的业务内容进行1\2\3\4二次校验，校验成功后在response中返回success，校验失败返回failure
//                callback(params.get("out_trade_no"), params.get("trade_no"));

                PaymentCompleteEvent event = new PaymentCompleteEvent(this, params.get("out_trade_no"), params.get("trade_no"), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(params.get("gmt_payment")));
                context.publishEvent(event);
                return "success";
            }else{
                // TODO 验签失败则记录异常日志，并在response中返回failure.
                return "failure";
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return "failure";
        }
    }
}
